import { createElement, ReactNode, JSXElementConstructor, ReactElement, ReactPortal } from "react";
import { createRoot } from 'react-dom/client';
import Alert from "./alert";

/**
 * @param type 消息类型
 * @param title 消息标题
 * @param description 消息描述
 * @param closable 是否显示关闭按钮
 * @param center 文字是否居中
 * @param showIcon 是否显示消息类型图标
 * @param messageTitle 标题插槽
 * @param messageDescription 描述插槽
 * @param duration 延时多少毫秒关闭
 * @param effect 主题
 */
interface Option {
    type?: "success" | "info" | "warning" | "error"
    title?: ReactNode,
    description?: ReactNode,
    closable?: boolean,
    center?: boolean,
    showIcon?: boolean,
    duration?: number,
    effect?: 'light' | 'dark',
    onClose?: () => void
}

class PeMessage {
    static zIndex = 8000

    // 新增文本消息
    static setDom = (dom: string | number | boolean | ReactElement<any, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | null | undefined, duration: number = 3000) => {
        const div = document.createElement("div")
        div.style.zIndex = `${++this.zIndex}`
        div.className = "pe-message pe-message-in"
        document.body.insertBefore(div, document.body.lastChild)
        const root = createRoot(div)
        root.render(dom)
        this.getTop()
        if (duration > 0) {
            setTimeout(() => {
                this.removeDom(div)
            }, duration)
        }
    }

    // 新增配置消息
    static setOptionDom = (
        {
            title = "",
            type = "info",
            description,
            closable = false,
            center = false,
            showIcon = true,
            duration = 3000,
            effect = 'light',
            onClose = () => { }
        }: Option,
        flag: "success" | "info" | "warning" | "error" | "" = ""
    ) => {
        const div = document.createElement("div")
        div.style.zIndex = `${++this.zIndex}`
        div.className = "pe-message pe-message-in"
        document.body.insertBefore(div, document.body.lastChild)
        const root = createRoot(div)
        root.render(createElement(Alert, {
            title, type: flag ? flag : type, description, showIcon, center, closable, effect,
            close: () => {
                onClose()
                this.removeDom(div)
            }
        }))
        this.getTop()
        if (duration > 0) {
            setTimeout(() => {
                this.removeDom(div)
            }, duration)
        }
    }

    // 获取top
    static getTop = () => {
        const domList = document.querySelectorAll<HTMLDivElement>(".pe-message-in")
        let top = 20
        for (const dom of domList) {
            dom.style.top = `${top}px`
            top += dom.offsetHeight + 20
        }
    }

    // 销毁消息元素
    static removeDom = (div: HTMLElement) => {
        // 销毁动画
        div.className = "pe-message pe-message-out"
        this.getTop()
        setTimeout(() => {
            div.remove()
        }, 500)
    }

    static success = (option: Option | string) => {
        if (typeof option === 'string') {
            this.setDom(createElement(Alert, { title: option, type: "success" }))
        } else {
            this.setOptionDom(option, "success")
        }
    }

    static info = (option: Option | string) => {
        if (typeof option === 'string') {
            this.setDom(createElement(Alert, { title: option, type: "info" }))
        } else {
            this.setOptionDom(option, "info")
        }
    }

    static warning = (option: Option | string) => {
        if (typeof option === 'string') {
            this.setDom(createElement(Alert, { title: option, type: "warning" }))
        } else {
            this.setOptionDom(option, "warning")
        }
    }

    static error = (option: Option | string) => {
        if (typeof option === 'string') {
            this.setDom(createElement(Alert, { title: option, type: "error" }))
        } else {
            this.setOptionDom(option, "error")
        }
    }

    static message = (option: Option) => {
        return this.setOptionDom(option)
    }
}

export default PeMessage